package ldh.database;

import ldh.database.util.MetaUtil;

import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class DbInfo {

    private Map<String, Table> tableMap = new TreeMap<String, Table>();
    private List<String[]> tables;
    private String db;
    private Connection connection;

    public DbInfo(Connection connection, String db) {
        this.connection = connection;
        this.db = db;
        asychnLoadTables(connection, db, null);
    }

    private void asychnLoadTables(Connection connection, String db, String owner) {
        tables = MetaUtil.getAllTable(connection, owner, db);

        for (String[] tableInfo : tables) {
            loanTable(tableInfo[0]);
        }
        buildAssociation();
    }

    private void loanTableInfo(String db, Connection connection, String[] tableInfo) {
        try {
            String tableName = tableInfo[0];
            String tableComment = tableInfo[1];
            Table table = MetaUtil.getTable(connection, "%", db, tableName);
            tableMap.put(tableName, table);//改变column对应java的类型
            if (table.getPrimaryKey() == null) {
                return;
            }

            table.setComment(tableComment);

        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    //即使外键也是索引的为多对多的中间表
    private boolean isManyToMany(Table table) {
        return table.getForeignKeys().size() == 2 && table.getColumnList().size() <= 4;
    }

    private boolean isOneToOne(Table table, ForeignKey fk) {
        if (table.getIndexies()!= null) {
            for (UniqueIndex ic : table.getIndexies()) {
                if (table.getForeignKeys() != null && ic.getColumns().size() == 1) {
                    for (String name : ic.getColumnNames()) {
                        if (name.equals(fk.getColumn().getName())) {
                            return true;
                        }
                    }

                }
            }
        }
        return false;
    }

    public Table getTable(String tableName) {
        return tableMap.get(tableName);
    }

    public List<String[]> getTables() {
        return tables;
    }

    public void loanTable(String tableName) {
        String[] tableInfo2 = null;
        for (String[] tableInfo : tables) {
            if(tableInfo[0].equals(tableName)) {
                tableInfo2 = tableInfo;
                break;
            }
        }
        if (tableMap.get(tableName) == null || tableMap.get(tableName).getColumnList() == null) {
            loanTableInfo(db, connection, tableInfo2);
        }
    }

    private void buildAssociation() {
        for (Map.Entry<String, Table> entry : tableMap.entrySet()) {
            Table table = entry.getValue();
            if (table == null) continue;
            if (table.getForeignKeys() != null && table.getForeignKeys().size() > 0) {
                for (ForeignKey fc : table.getForeignKeys()) {
                    fc.setForeignTable(tableMap.get(fc.getForeignTableName()));
                    System.out.println("tableName: " + table.getName() + ", fk:" + fc);
                    if (isOneToOne(table, fc)) {
                        fc.setOneToOne(true);
                        fc.getColumn().setOneToOne(true);
                    }
                }
            }
        }

        //建立多对多关系
        for (Map.Entry<String, Table> entry : tableMap.entrySet()) {
            Table table = entry.getValue();
            if (table == null) continue;
            boolean isMtm = isManyToMany(table);
            if (isMtm) {
                Table one = null, two = null;
                ForeignKey onFk = null, twoFk = null;
                for(ForeignKey fk : table.getForeignKeys()) {
                    if (one == null) {
                        one = fk.getForeignTable();
                        onFk = fk;
                    } else {
                        two = fk.getForeignTable();
                        twoFk = fk;
                    }
                }
                ManyToMany mtm = new ManyToMany(one, onFk, two, twoFk, table);
                ManyToMany mtm2 = new ManyToMany(two, twoFk, one, onFk, table);
                one.addManyToMany(mtm);
                two.addManyToMany(mtm2);
                table.setMiddle(true);
            }
        }
    }

    public Map<String, Table> getTableMap() {
        return tableMap;
    }

    public void setTableMap(Map<String, Table> tableMap) {
        this.tableMap = tableMap;
    }

    public void setTables(List<String[]> tables) {
        this.tables = tables;
    }

    public String getDb() {
        return db;
    }

    public void setDb(String db) {
        this.db = db;
    }

    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }
}
